package game.metalmax.animation.zone
{
	import flash.geom.Point;
	import flash.ui.Keyboard;
	
	import game.metalmax.animation.CharacterSOB;
	import game.metalmax.animation.HeroSOB;
	import game.metalmax.animation.TankSOB;
	import game.metalmax.config.GameConfig;
	import game.metalmax.controller.Notifications;
	import game.metalmax.entity.character.Character;
	import game.metalmax.entity.character.Hero;
	import game.metalmax.factory.AbstractFactory;
	import game.metalmax.factory.SOBFactory;
	import game.metalmax.module.character.CharacterManager;
	import game.metalmax.module.world.WorldManager;
	import game.metalmax.module.world.WorldProxy;
	
	import showtime.framework.component.loading.GroupLoader;
	import showtime.framework.engine.Direction;
	import showtime.framework.engine.Scene2D;
	import showtime.framework.engine.World2D;
	import showtime.framework.engine.input.Mouse;
	import showtime.framework.engine.map.parser.TiledParser;
	import showtime.framework.engine.map.rpg.ObjectHolder;
	import showtime.framework.engine.map.rpg.RPGGameMap;
	import showtime.framework.events.AnimationMouseEvent;
	import showtime.framework.events.GameEvent;
	import showtime.framework.events.MessageDispatcher;
	import showtime.framework.manager.AssetManager;
	import showtime.framework.music.Music;
	import showtime.framework.mvc.patterns.facade.Facade;
	import showtime.framework.utils.CallbackBean;
	
	public class SceneZone extends Scene2D
	{
		public var map:RPGGameMap = null;
		
		public var target:CharacterSOB = null;
		
		public var music:Music = null;

		public function SceneZone()
		{
			
		}
		
		override public function create():void
		{
			super.create();
			
			MessageDispatcher.getInstance().addEventListener(GameEvent.SCENE_OBJECT_ADD, sceneObjectAddHandler);
			MessageDispatcher.getInstance().addEventListener(GameEvent.OBJECT_MOVE_STOP, objectMoveStopHandler);
			MessageDispatcher.getInstance().addEventListener(GameEvent.OBJECT_MOVE_START, objectMoveStartHandler);
			MessageDispatcher.getInstance().addEventListener(GameEvent.OBJECT_GROUP_MOVE_STOP, objectGroupMoveStopHandler);
			addEventListener(AnimationMouseEvent.CLICK, animationClickHandler);			
			addEventListener(AnimationMouseEvent.ROLL_OVER, animationRollOverHandler);
			addEventListener(AnimationMouseEvent.ROLL_OUT, animationRollOutHandler);
			
			loadingAssets();
		}	
		
		private function loadingAssets():void
		{			
			var callback:CallbackBean = new CallbackBean();
			callback.source = this;
			callback.data = [GameConfig.URL_MAP_TMX + WorldManager.getInstance().nowMapID + ".tmx"];
			callback.method = loadingAssetsSuccess;			
			Facade.getInstance().sendNotification(Notifications.NOW_LOADING, callback);
			
		}	
		
		private function loadingAssetsSuccess(loader:GroupLoader):void
		{
			music = new Music();
			//music.loadClass(AssetManager.getInstance().getClass("com.metalmax.music.themes.TownTheme")).play();
			
			registerMap(loader.getXML(WorldManager.getInstance().nowMapID));
			
			registerSOBFromLocal();
			
			loader.unload();
			
			WorldProxy(Facade.getInstance().retrieveProxy(String(WorldProxy))).enterSceneC2S(WorldManager.getInstance().nowMapID);
		}
		
		override public function update():void
		{
			super.update();
			
			if (!active || map == null || target.running)
			{
				return;
			}
			
			if (World2D.keyboard.down(Keyboard.SPACE))
			{
				execute();
			}	
			else if (World2D.keyboard.down(Keyboard.ENTER))
			{
				Facade.getInstance().sendNotification(Notifications.OPEN_MAIN_WINDOW);
			}
			else if (World2D.keyboard.down(Keyboard.S) || World2D.keyboard.down(Keyboard.DOWN))
			{
				target.moveTo(Direction.BOTTOM);				
			}
			else if (World2D.keyboard.down(Keyboard.W) || World2D.keyboard.down(Keyboard.UP))
			{
				target.moveTo(Direction.TOP);
			}
			else if (World2D.keyboard.down(Keyboard.A) || World2D.keyboard.down(Keyboard.LEFT))
			{
				target.moveTo(Direction.LEFT);				
			}
			else if (World2D.keyboard.down(Keyboard.D) || World2D.keyboard.down(Keyboard.RIGHT))
			{
				target.moveTo(Direction.RIGHT);
			}
			else if (World2D.mouse.down(Mouse.LEFT))
			{
				var globalPoint:Point = map.target.parent.localToGlobal(new Point(map.target.x, map.target.y));
				var dx:Number = mouseX - globalPoint.x;
				var dy:Number = mouseY - globalPoint.y;		
				var distance:Number = Math.sqrt(dx * dx + dy * dy);			
				var cos:Number = dx / distance;
				var angle:int = int(Math.floor(Math.acos(cos) * 180 / Math.PI));
				
				if (dy < 0)
				{
					angle = 360 - angle;
				}
				
				if (angle > 315 || angle < 45)
				{
					target.moveTo(Direction.RIGHT);
				}
				else if (angle > 225)
				{
					target.moveTo(Direction.TOP);
				}
				else if (angle > 135)
				{
					target.moveTo(Direction.LEFT);
				}
				else
				{
					target.moveTo(Direction.BOTTOM);	
				}
			}
		}
		
		override public function destroy():void
		{
			super.destroy();					
			MessageDispatcher.getInstance().removeEventListener(GameEvent.OBJECT_MOVE_STOP, objectMoveStopHandler);
			MessageDispatcher.getInstance().removeEventListener(GameEvent.OBJECT_MOVE_START, objectMoveStartHandler);	
			MessageDispatcher.getInstance().removeEventListener(GameEvent.OBJECT_GROUP_MOVE_STOP, objectGroupMoveStopHandler);
			MessageDispatcher.getInstance().removeEventListener(GameEvent.SCENE_OBJECT_ADD, sceneObjectAddHandler);

			map = null;			
			target = null;
			
			music != null && music.stop();
			
			music = null;
		}	
		
		protected function objectMoveStartHandler(evt:GameEvent):void
		{				
			if (evt.data == CharacterManager.getInstance().self)
			{
				var event:ObjectHolder = map.getEvent(target.getNextPoint());			
				
				event != null && WorldManager.getInstance().preHandleEvent(event);				
				
			}			
		}
		
		protected function objectMoveStopHandler(evt:GameEvent):void
		{		
			if (evt.data == CharacterManager.getInstance().self)
			{								
				var event:ObjectHolder = map.getEvent(target.getNowPoint());			
				
				event != null && WorldManager.getInstance().postHandleEvent(event);
				
				target != null && WorldProxy(Facade.getInstance().retrieveProxy(String(WorldProxy))).moveHeroC2S(target.x, target.y);
				
			}
		}
		
		protected function objectGroupMoveStopHandler(evt:GameEvent):void
		{
			if (target == null)
			{
				return;
			}
			
			WorldManager.getInstance().restoreObjects();			
			
			var tempTarget:CharacterSOB = target;
			var event:ObjectHolder = null;			
			while (tempTarget != null && map != null)
			{
				event = map.getEvent(tempTarget.getNowPoint());						
				event != null && WorldManager.getInstance().postHandleEvent(event);	
				
				if (tempTarget.followTarget != null)
				{
					var dx:Number = tempTarget.x - tempTarget.followTarget.x;
					var dy:Number = tempTarget.y - tempTarget.followTarget.y;
					
					var angle:int = Math.atan2(dy, dx);				
					
					switch (angle)
					{
						case 0:
						{
							tempTarget.followTarget.play(CharacterSOB.getIdleAnimationNameByDirection(Direction.RIGHT));
							tempTarget.followTarget.direction = Direction.RIGHT;
							
							break;
						}
						case 1:
						{
							tempTarget.followTarget.play(CharacterSOB.getIdleAnimationNameByDirection(Direction.BOTTOM));
							tempTarget.followTarget.direction = Direction.BOTTOM;
							
							break;
						}
						case -1:
						{
							tempTarget.followTarget.play(CharacterSOB.getIdleAnimationNameByDirection(Direction.TOP));
							tempTarget.followTarget.direction = Direction.TOP;
							
							break;
						}
						case 3:
						{
							tempTarget.followTarget.play(CharacterSOB.getIdleAnimationNameByDirection(Direction.LEFT));
							tempTarget.followTarget.direction = Direction.LEFT;
							
							break;
						}
					}
				}
				else
				{					
					tempTarget.lastDirection = tempTarget.direction;
				}
				tempTarget = tempTarget.followTarget;					
			}
			
		}
		
		private function sceneObjectAddHandler(evt:GameEvent):void
		{
			registerSOBFromServer(evt.data as Array);
		}
		
		protected function execute():void
		{ 
			var event:ObjectHolder = null;
			
			switch (target.direction)
			{
				case Direction.TOP:
				{
					event = map.getEvent(target.getTopTile());					
					break;
				}
				case Direction.BOTTOM:
				{
					event = map.getEvent(target.getBottomTile());
					break;
				}
				case Direction.LEFT:
				{
					event = map.getEvent(target.getLeftTile());
					break;
				}
				case Direction.RIGHT:
				{
					event = map.getEvent(target.getRightTile());
					break;
				}
			}
			
			if (event != null)
			{
				WorldManager.getInstance().postHandleEvent(event);
				return;
			}
			
			var object:Object = map.getObjectByTarget(target);
			if (object != null)
			{
				WorldManager.getInstance().postHandleObject(object);
			}
			
			if (object == null)
			{
				switch (target.direction)
				{
					case Direction.TOP:
					{
						object = map.getObjectByPoint(target.getTopTile());					
						break;
					}
					case Direction.BOTTOM:
					{
						object = map.getObjectByPoint(target.getBottomTile());
						break;
					}
					case Direction.LEFT:
					{
						object = map.getObjectByPoint(target.getLeftTile());
						break;
					}
					case Direction.RIGHT:
					{
						object = map.getObjectByPoint(target.getRightTile());
						break;
					}
				}
			}			
			
			if (object != null && !(object is TankSOB && (object.x == target.x || object.y == target.y)))
			{				
				WorldManager.getInstance().postHandleObject(object);
			}
			
		}
		
		private function animationClickHandler(evt:AnimationMouseEvent):void
		{
			evt.data.click();
		}
		
		private function animationRollOverHandler(evt:AnimationMouseEvent):void
		{
			evt.data.rollOver();
		}
		
		private function animationRollOutHandler(evt:AnimationMouseEvent):void
		{
			evt.data.rollOut();
		}
		
		private function registerMap(cofig:XML):void
		{			
			var parser:TiledParser = new TiledParser();
			parser.loadFromXML(cofig);
			parser.parse();
			map = new RPGGameMap(GameConfig.SCREEN_WIDTH, GameConfig.SCREEN_HEIGHT, parser.layers, parser.groups, AssetManager.getInstance().getGraphic("METAL_MAX_MAP_TILE"), 15, 15);		
			
			parser.destroy();
			
			addEntity(map);
		}
		
		private function registerSOB(object:ObjectHolder):void
		{
			map.addObect(AbstractFactory.getFactory(SOBFactory).create(object));
		}
		
		private function registerSOBFromServer(objects:Array):void
		{
			for each (var object:ObjectHolder in objects)
			{
				registerSOB(object);
			}
		}	
		
		private function registerSOBFromLocal():void
		{				
			for each (var object:ObjectHolder in map.objectGroup.objects)
			{
				registerSOB(object);
			}
			
			target = new HeroSOB(CharacterManager.getInstance().self);			
			map.follow(target);
			
			var _target:CharacterSOB = target;			
			for each (var hero:Hero in CharacterManager.getInstance().heros)
			{
				while (_target.followTarget != null)
				{
					_target = _target.followTarget;
				}
				
				_target.setFollowTarget(Character(hero), target.getNowPoint());
			}		
			
			
		}
	}
}